home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1994 November
/
macformat-018.iso
/
Utility Spectacular
/
Developer
/
macgambit-20-compiler-src-p2
/
Runtime (.scm & .s)
/
_numbers.scm
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1994-07-26
|
84.2 KB
|
2,622 lines
|
[
TEXT/gamI
]
(##include "header.scm")
;------------------------------------------------------------------------------
; Number stuff
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; There are 5 internal representations for numbers:
;
; fixnum, bignum, ratnum, flonum, cpxnum
;
; Fixnums and bignums form the class of exact-int.
; Fixnums, bignums and ratnums form the class of exact-real.
; Fixnums, bignums, ratnums and flonums form the class of non-cpxnum.
; The representation has some invariants:
;
; The numerator of a ratnum is an exact-int.
; The denominator of a ratnum is a positive (>1) exact-int.
; The numerator and denominator have no common divisors.
;
; The real part of a cpxnum is a non-cpxnum.
; The imaginary part of a cpxnum is a non-cpxnum != fixnum 0
; The following table gives the mapping of the Scheme exact numbers to their
; internal representation:
;
; type representation
; exact integer = exact-int (fixnum, bignum)
; exact rational = exact-real (fixnum, bignum, ratnum)
; exact real = exact-real (fixnum, bignum, ratnum)
; exact complex = exact-real or cpxnum with exact-real real and imag parts
; For inexact numbers, the representation is not quite as straightforward.
;
; There are 3 "special" classes of inexact representation:
; flonum-int : flonum with integer value
; cpxnum-real: cpxnum with imag part = flonum 0.0
; cpxnum-int : cpxnum-real with exact-int or flonum-int real part
;
; This gives to the following table for Scheme's inexact numbers:
;
; type representation
; inexact integer = flonum-int or cpxnum-int
; inexact rational = flonum or cpxnum-real
; inexact real = flonum or cpxnum-real
; inexact complex = flonum or cpxnum
(##define-macro (exact-int? x) ; x can be any object
`(or (##fixnum? ,x) (##bignum? ,x)))
(##define-macro (exact-real? x) ; x can be any object
`(or (exact-int? ,x) (##ratnum? ,x)))
(##define-macro (flonum-zero? x) ; x can be any object
`(and (##flonum? ,x) (##flonum.zero? ,x)))
(##define-macro (flonum-int? x) ; x must be a flonum
`(##flonum.= ,x (##flonum.truncate ,x)))
(##define-macro (non-cpxnum-int? x) ; x must be in fixnum/bignum/ratnum/flonum
`(if (##flonum? ,x) (flonum-int? ,x) (##not (##ratnum? ,x))))
(##define-macro (non-cpxnum-zero? x) ; x must be in fixnum/bignum/ratnum/flonum
`(if (##fixnum? ,x) (##fixnum.= ,x 0) (flonum-zero? ,x)))
(##define-macro (cpxnum-int? x) ; x must be a cpxnum
`(and (cpxnum-real? ,x)
(let ((real (cpxnum-real ,x))) (non-cpxnum-int? ,x))))
(##define-macro (cpxnum-real? x) ; x must be a cpxnum
`(let ((imag (cpxnum-imag ,x))) (flonum-zero? imag)))
(##define-macro (inexact-+2) 2.0)
(##define-macro (inexact--2) -2.0)
(##define-macro (inexact-+1) 1.0)
(##define-macro (inexact--1) -1.0)
(##define-macro (inexact-+1/2) 0.5)
(##define-macro (inexact-0) 0.0)
(##define-macro (inexact-+pi) 3.141592653589793)
(##define-macro (inexact--pi) -3.141592653589793)
(##define-macro (inexact-+pi/2) 1.5707963267948966)
(##define-macro (inexact--pi/2) -1.5707963267948966)
(##define-macro (cpxnum-+2i) +2i)
(##define-macro (cpxnum--i) -i)
(##define-macro (cpxnum-+i) +i)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Numerical type predicates
(define (##complex? x)
(number-dispatch x #f #t #t #t #t #t))
(define (##real? x)
(number-dispatch x #f #t #t #t #t (cpxnum-real? x)))
(define (##rational? x)
(number-dispatch x #f #t #t #t #t (cpxnum-real? x)))
(define (##integer? x)
(number-dispatch x #f #t #t #f (flonum-int? x) (cpxnum-int? x)))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Exactness predicates
(define (##exact? x)
(define (error) (##trap-check-number 'exact? x))
(number-dispatch x (error) #t #t #t #f
(and (##not (##flonum? (cpxnum-real x)))
(##not (##flonum? (cpxnum-imag x))))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Numerical comparison predicates
(define (##eqv? x y)
(number-dispatch x (##eq? x y)
(if (##fixnum? y) (##fixnum.= x y) #f)
(if (##bignum? y) (##bignum.= x y) #f)
(if (##ratnum? y) (##ratnum.= x y) #f)
(and (##complex? y) (##not (##exact? y)) (##= x y))
(and (##complex? y) (##eq? (##exact? x) (##exact? y)) (##= x y))))
(define (##= x y)
(define (error) (##trap-check-number '= x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(##fixnum.= x y)
#f
#f
(##flonum.= (##flonum.<-fixnum x) y)
(##cpxnum.= (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = bignum
#f
(##bignum.= x y)
#f
(##flonum.= (##flonum.<-bignum x) y)
(##cpxnum.= (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = ratnum
#f
#f
(##ratnum.= x y)
(##ratnum.= x (##flonum.->ratnum y))
(##cpxnum.= (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = flonum
(##ratnum.= (##flonum.->ratnum x) (##ratnum.<-exact-int y))
(##ratnum.= (##flonum.->ratnum x) (##ratnum.<-exact-int y))
(##ratnum.= (##flonum.->ratnum x) y)
(##flonum.= x y)
(##cpxnum.= (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = cpxnum
(##cpxnum.= x (##cpxnum.<-non-cpxnum y))
(##cpxnum.= x (##cpxnum.<-non-cpxnum y))
(##cpxnum.= x (##cpxnum.<-non-cpxnum y))
(##cpxnum.= x (##cpxnum.<-non-cpxnum y))
(##cpxnum.= x y))))
(define (##< x y)
(define (error) (##trap-check-real '< x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(##fixnum.< x y)
(bignum-positive? y)
(##ratnum.< (##ratnum.<-exact-int x) y)
(##flonum.< (##flonum.<-fixnum x) y)
(if (cpxnum-real? y) (##< x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = bignum
(bignum-negative? x)
(##bignum.< x y)
(##ratnum.< (##ratnum.<-exact-int x) y)
(##flonum.< (##flonum.<-bignum x) y)
(if (cpxnum-real? y) (##< x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = ratnum
(##ratnum.< x (##ratnum.<-exact-int y))
(##ratnum.< x (##ratnum.<-exact-int y))
(##ratnum.< x y)
(##ratnum.< x (##flonum.->ratnum y))
(if (cpxnum-real? y) (##< x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = flonum
(##ratnum.< (##flonum.->ratnum x) (##ratnum.<-exact-int y))
(##ratnum.< (##flonum.->ratnum x) (##ratnum.<-exact-int y))
(##ratnum.< (##flonum.->ratnum x) y)
(##flonum.< x y)
(if (cpxnum-real? y) (##< x (cpxnum-real y)) (error)))
(if (cpxnum-real? x) ; x = cpxnum
(number-dispatch y (error)
(##< (cpxnum-real x) y)
(##< (cpxnum-real x) y)
(##< (cpxnum-real x) y)
(##< (cpxnum-real x) y)
(if (cpxnum-real? y) (##< (cpxnum-real x) (cpxnum-real y)) (error)))
(error))))
(define (##zero? x)
(define (error) (##trap-check-number 'zero? x))
(number-dispatch x (error) (##fixnum.= x 0) #f #f (##flonum.zero? x)
(let ((imag (cpxnum-imag x)))
(and (flonum-zero? imag)
(let ((real (cpxnum-real x)))
(non-cpxnum-zero? real))))))
(define (##positive? x)
(define (error) (##trap-check-real 'positive? x))
(number-dispatch x (error)
(##fixnum.positive? x)
(bignum-positive? x)
(##positive? (ratnum-numerator x))
(##flonum.positive? x)
(if (cpxnum-real? x) (##positive? (cpxnum-real x)) (error))))
(define (##negative? x)
(define (error) (##trap-check-real 'negative? x))
(number-dispatch x (error)
(##fixnum.negative? x)
(bignum-negative? x)
(##negative? (ratnum-numerator x))
(##flonum.negative? x)
(if (cpxnum-real? x) (##negative? (cpxnum-real x)) (error))))
(define (##odd? x)
(define (error) (##trap-check-integer 'odd? x))
(number-dispatch x (error)
(##fixnum.odd? x)
(bignum-odd? x)
(error)
(if (flonum-int? x) (##odd? (##flonum.->exact-int x)) (error))
(if (cpxnum-int? x) (##odd? (cpxnum-real x)) (error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Max and min
(define (##max x y)
(define (error) (##trap-check-real 'max x y))
(define (m x y) (if (##< x y) y x))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(m x y)
(m x y)
(m x y)
(if (##< x y) y (##flonum.<-fixnum x))
(if (cpxnum-real? y) (##max x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = bignum
(m x y)
(m x y)
(m x y)
(if (##< x y) y (##flonum.<-bignum x))
(if (cpxnum-real? y) (##max x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = ratnum
(m x y)
(m x y)
(m x y)
(if (##< x y) y (##flonum.<-ratnum x))
(if (cpxnum-real? y) (##max x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = flonum
(if (##< x y) (##flonum.<-fixnum y) x)
(if (##< x y) (##flonum.<-bignum y) x)
(if (##< x y) (##flonum.<-ratnum y) x)
(m x y)
(if (cpxnum-real? y) (##max x (cpxnum-real y)) (error)))
(if (cpxnum-real? x) ; x = cpxnum
(number-dispatch y (error)
(##max (cpxnum-real x) y)
(##max (cpxnum-real x) y)
(##max (cpxnum-real x) y)
(##max (cpxnum-real x) y)
(if (cpxnum-real? y) (##max (cpxnum-real x) (cpxnum-real y)) (error)))
(error))))
(define (##min x y)
(define (error) (##trap-check-real 'min x y))
(define (m x y) (if (##< x y) x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(m x y)
(m x y)
(m x y)
(if (##< x y) (##flonum.<-fixnum x) y)
(if (cpxnum-real? y) (##min x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = bignum
(m x y)
(m x y)
(m x y)
(if (##< x y) (##flonum.<-bignum x) y)
(if (cpxnum-real? y) (##min x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = ratnum
(m x y)
(m x y)
(m x y)
(if (##< x y) (##flonum.<-ratnum x) y)
(if (cpxnum-real? y) (##min x (cpxnum-real y)) (error)))
(number-dispatch y (error) ; x = flonum
(if (##< x y) x (##flonum.<-fixnum y))
(if (##< x y) x (##flonum.<-bignum y))
(if (##< x y) x (##flonum.<-ratnum y))
(m x y)
(if (cpxnum-real? y) (##min x (cpxnum-real y)) (error)))
(if (cpxnum-real? x) ; x = cpxnum
(number-dispatch y (error)
(##min (cpxnum-real x) y)
(##min (cpxnum-real x) y)
(##min (cpxnum-real x) y)
(##min (cpxnum-real x) y)
(if (cpxnum-real? y) (##min (cpxnum-real x) (cpxnum-real y)) (error)))
(error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; +, *, -, /
(define (##+ x y)
(define (error) (##trap-check-number '+ x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(##bignum.+/fixnum-fixnum x y)
(##bignum.+/bignum-fixnum y x)
(##ratnum.+ (##ratnum.<-exact-int x) y)
(##flonum.+ (##flonum.<-fixnum x) y)
(##cpxnum.+ (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = bignum
(##bignum.+/bignum-fixnum x y)
(##bignum.+ x y)
(##ratnum.+ (##ratnum.<-exact-int x) y)
(##flonum.+ (##flonum.<-bignum x) y)
(##cpxnum.+ (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = ratnum
(##ratnum.+ x (##ratnum.<-exact-int y))
(##ratnum.+ x (##ratnum.<-exact-int y))
(##ratnum.+ x y)
(##flonum.+ (##flonum.<-ratnum x) y)
(##cpxnum.+ (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = flonum
(##flonum.+ x (##flonum.<-fixnum y))
(##flonum.+ x (##flonum.<-bignum y))
(##flonum.+ x (##flonum.<-ratnum y))
(##flonum.+ x y)
(##cpxnum.+ (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = cpxnum
(##cpxnum.+ x (##cpxnum.<-non-cpxnum y))
(##cpxnum.+ x (##cpxnum.<-non-cpxnum y))
(##cpxnum.+ x (##cpxnum.<-non-cpxnum y))
(##cpxnum.+ x (##cpxnum.<-non-cpxnum y))
(##cpxnum.+ x y))))
(define (##* x y)
(define (error) (##trap-check-number '* x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(##bignum.*/fixnum-fixnum x y)
(##bignum.*/bignum-fixnum y x)
(##ratnum.* (##ratnum.<-exact-int x) y)
(##flonum.* (##flonum.<-fixnum x) y)
(##cpxnum.* (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = bignum
(##bignum.*/bignum-fixnum x y)
(##bignum.* x y)
(##ratnum.* (##ratnum.<-exact-int x) y)
(##flonum.* (##flonum.<-bignum x) y)
(##cpxnum.* (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = ratnum
(##ratnum.* x (##ratnum.<-exact-int y))
(##ratnum.* x (##ratnum.<-exact-int y))
(##ratnum.* x y)
(##flonum.* (##flonum.<-ratnum x) y)
(##cpxnum.* (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = flonum
(##flonum.* x (##flonum.<-fixnum y))
(##flonum.* x (##flonum.<-bignum y))
(##flonum.* x (##flonum.<-ratnum y))
(##flonum.* x y)
(##cpxnum.* (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = cpxnum
(##cpxnum.* x (##cpxnum.<-non-cpxnum y))
(##cpxnum.* x (##cpxnum.<-non-cpxnum y))
(##cpxnum.* x (##cpxnum.<-non-cpxnum y))
(##cpxnum.* x (##cpxnum.<-non-cpxnum y))
(##cpxnum.* x y))))
(define (##- x y)
(define (error) (##trap-check-number '- x y))
(number-dispatch x (error)
(number-dispatch y (error) ; x = fixnum
(##bignum.-/fixnum-fixnum x y)
(##bignum.-/fixnum-bignum x y)
(##ratnum.- (##ratnum.<-exact-int x) y)
(##flonum.- (##flonum.<-fixnum x) y)
(##cpxnum.- (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = bignum
(##bignum.-/bignum-fixnum x y)
(##bignum.- x y)
(##ratnum.- (##ratnum.<-exact-int x) y)
(##flonum.- (##flonum.<-bignum x) y)
(##cpxnum.- (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = ratnum
(##ratnum.- x (##ratnum.<-exact-int y))
(##ratnum.- x (##ratnum.<-exact-int y))
(##ratnum.- x y)
(##flonum.- (##flonum.<-ratnum x) y)
(##cpxnum.- (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = flonum
(##flonum.- x (##flonum.<-fixnum y))
(##flonum.- x (##flonum.<-bignum y))
(##flonum.- x (##flonum.<-ratnum y))
(##flonum.- x y)
(##cpxnum.- (##cpxnum.<-non-cpxnum x) y))
(number-dispatch y (error) ; x = cpxnum
(##cpxnum.- x (##cpxnum.<-non-cpxnum y))
(##cpxnum.- x (##cpxnum.<-non-cpxnum y))
(##cpxnum.- x (##cpxnum.<-non-cpxnum y))
(##cpxnum.- x (##cpxnum.<-non-cpxnum y))
(##cpxnum.- x y))))
(define (##/ x y)
(define (divide-by-zero) (##trap-divide-by-zero '/ x y))
(define (error) (##trap-check-number '/ x y))
(number-dispatch y (error)
(if (##fixnum.= y 0) ; y = fixnum
(divide-by-zero)
(number-dispatch x (error)
(##ratnum./ (##ratnum.<-exact-int x) (##ratnum.<-exact-int y))
(##ratnum./ (##ratnum.<-exact-int x) (##ratnum.<-exact-int y))
(##ratnum./ x (##ratnum.<-exact-int y))
(##flonum./ x (##flonum.<-fixnum y))
(##cpxnum./ x (##cpxnum.<-non-cpxnum y))))
(number-dispatch x (error) ; y = bignum
(##ratnum./ (##ratnum.<-exact-int x) (##ratnum.<-exact-int y))
(##ratnum./ (##ratnum.<-exact-int x) (##ratnum.<-exact-int y))
(##ratnum./ x (##ratnum.<-exact-int y))
(##flonum./ x (##flonum.<-bignum y))
(##cpxnum./ x (##cpxnum.<-non-cpxnum y)))
(number-dispatch x (error) ; y = ratnum
(##ratnum./ (##ratnum.<-exact-int x) y)
(##ratnum./ (##ratnum.<-exact-int x) y)
(##ratnum./ x y)
(##flonum./ x (##flonum.<-ratnum y))
(##cpxnum./ x (##cpxnum.<-non-cpxnum y)))
(if (##flonum.zero? y) ; y = flonum
(divide-by-zero)
(number-dispatch x (error)
(##flonum./ (##flonum.<-fixnum x) y)
(##flonum./ (##flonum.<-bignum x) y)
(##flonum./ (##flonum.<-ratnum x) y)
(##flonum./ x y)
(##cpxnum./ x (##cpxnum.<-non-cpxnum y))))
(let ((imag (cpxnum-imag y))) ; y = cpxnum
(if (and (flonum-zero? imag)
(let ((real (cpxnum-real y)))
(non-cpxnum-zero? real)))
(divide-by-zero)
(number-dispatch x (error)
(##cpxnum./ (##cpxnum.<-non-cpxnum x) y)
(##cpxnum./ (##cpxnum.<-non-cpxnum x) y)
(##cpxnum./ (##cpxnum.<-non-cpxnum x) y)
(##cpxnum./ (##cpxnum.<-non-cpxnum x) y)
(##cpxnum./ x y))))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; abs
(define (##abs x)
(define (error) (##trap-check-real 'abs x))
(number-dispatch x (error)
(if (##fixnum.negative? x) (##bignum.-/fixnum-fixnum 0 x) x)
(if (bignum-negative? x) (##bignum.-/fixnum-bignum 0 x) x)
(if (##negative? (ratnum-numerator x))
(ratnum-make (##- 0 (ratnum-numerator x)) (ratnum-denominator x))
x)
(##flonum.abs x)
(if (cpxnum-real? x) (##abs (cpxnum-real x)) (error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; quotient, remainder, modulo
(define (##quotient x y)
(define (divide-by-zero) (##trap-divide-by-zero 'quotient x y))
(define (error) (##trap-check-integer 'quotient x y))
(define (inexact-quotient)
(##exact->inexact (##quotient (##inexact->exact x) (##inexact->exact y))))
(number-dispatch y (error)
(if (##fixnum.= y 0) ; y = fixnum
(divide-by-zero)
(number-dispatch x (error)
(if (##fixnum.= y -1)
(##bignum.-/fixnum-fixnum 0 x)
(##fixnum.quotient x y))
(##bignum.quotient/bignum-fixnum x y)
(error)
(if (flonum-int? x) (inexact-quotient) (error))
(if (cpxnum-int? x) (inexact-quotient) (error))))
(number-dispatch x (error) ; y = bignum
(##bignum.quotient/fixnum-bignum x y)
(##bignum.quotient x y)
(error)
(if (flonum-int? x) (inexact-quotient) (error))
(if (cpxnum-int? x) (inexact-quotient) (error)))
(error) ; y = ratnum
(if (flonum-int? y) ; y = flonum
(number-dispatch x (error)
(inexact-quotient)
(inexact-quotient)
(error)
(if (flonum-int? x) (inexact-quotient) (error))
(if (cpxnum-int? x) (inexact-quotient) (error)))
(error))
(if (cpxnum-int? y) ; y = cpxnum
(number-dispatch x (error)
(inexact-quotient)
(inexact-quotient)
(error)
(if (flonum-int? x) (inexact-quotient) (error))
(if (cpxnum-int? x) (inexact-quotient) (error)))
(error))))
(define (##remainder x y)
(define (divide-by-zero) (##trap-divide-by-zero 'remainder x y))
(define (error) (##trap-check-integer 'remainder x y))
(define (inexact-remainder)
(##exact->inexact (##remainder (##inexact->exact x) (##inexact->exact y))))
(number-dispatch y (error)
(if (##fixnum.= y 0) ; y = fixnum
(divide-by-zero)
(number-dispatch x (error)
(##fixnum.remainder x y)
(##bignum.remainder/bignum-fixnum x y)
(error)
(if (flonum-int? x) (inexact-remainder) (error))
(if (cpxnum-int? x) (inexact-remainder) (error))))
(number-dispatch x (error) ; y = bignum
(##bignum.remainder/fixnum-bignum x y)
(##bignum.remainder x y)
(error)
(if (flonum-int? x) (inexact-remainder) (error))
(if (cpxnum-int? x) (inexact-remainder) (error)))
(error) ; y = ratnum
(if (flonum-int? y) ; y = flonum
(number-dispatch x (error)
(inexact-remainder)
(inexact-remainder)
(error)
(if (flonum-int? x) (inexact-remainder) (error))
(if (cpxnum-int? x) (inexact-remainder) (error)))
(error))
(if (cpxnum-int? y) ; y = cpxnum
(number-dispatch x (error)
(inexact-remainder)
(inexact-remainder)
(error)
(if (flonum-int? x) (inexact-remainder) (error))
(if (cpxnum-int? x) (inexact-remainder) (error)))
(error))))
(define (##modulo x y)
(define (divide-by-zero) (##trap-divide-by-zero 'modulo x y))
(define (error) (##trap-check-integer 'modulo x y))
(define (inexact-modulo)
(##exact->inexact (##modulo (##inexact->exact x) (##inexact->exact y))))
(number-dispatch y (error)
(if (##fixnum.= y 0) ; y = fixnum
(divide-by-zero)
(number-dispatch x (error)
(##fixnum.modulo x y)
(##bignum.modulo/bignum-fixnum x y)
(error)
(if (flonum-int? x) (inexact-modulo) (error))
(if (cpxnum-int? x) (inexact-modulo) (error))))
(number-dispatch x (error) ; y = bignum
(##bignum.modulo/fixnum-bignum x y)
(##bignum.modulo x y)
(error)
(if (flonum-int? x) (inexact-modulo) (error))
(if (cpxnum-int? x) (inexact-modulo) (error)))
(error) ; y = ratnum
(if (flonum-int? y) ; y = flonum
(number-dispatch x (error)
(inexact-modulo)
(inexact-modulo)
(error)
(if (flonum-int? x) (inexact-modulo) (error))
(if (cpxnum-int? x) (inexact-modulo) (error)))
(error))
(if (cpxnum-int? y) ; y = cpxnum
(number-dispatch x (error)
(inexact-modulo)
(inexact-modulo)
(error)
(if (flonum-int? x) (inexact-modulo) (error))
(if (cpxnum-int? x) (inexact-modulo) (error)))
(error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; gcd, lcm
(define (##gcd x y)
(define (exact-gcd x y)
(let loop ((x (##abs x)) (y (##abs y)))
(if (##eq? y 0) x (loop y (##remainder x y)))))
(if (and (##integer? x) (##integer? y))
(if (and (##exact? x) (##exact? y))
(exact-gcd x y)
(##exact->inexact (exact-gcd (##inexact->exact x) (##inexact->exact y))))
(##trap-check-integer 'gcd x y)))
(define (##lcm x y)
(define (exact-gcd x y)
(let loop ((x (##abs x)) (y (##abs y)))
(if (##eq? y 0) x (loop y (##remainder x y)))))
(define (exact-lcm x y)
(if (or (##eq? x 0) (##eq? y 0))
0
(##quotient (##abs (##* x y)) (exact-gcd x y))))
(if (and (##integer? x) (##integer? y))
(if (and (##exact? x) (##exact? y))
(exact-lcm x y)
(##exact->inexact (exact-lcm (##inexact->exact x) (##inexact->exact y))))
(##trap-check-integer 'lcm x y)))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; numerator, denominator
(define (##numerator x)
(define (error) (##trap-check-rational 'numerator x))
(number-dispatch x (error)
x
x
(ratnum-numerator x)
(##numerator (##flonum.inexact->exact x))
(if (cpxnum-real? x) (##numerator (cpxnum-real x)) (error))))
(define (##denominator x)
(define (error) (##trap-check-rational 'denominator x))
(number-dispatch x (error)
1
1
(ratnum-denominator x)
(##denominator (##flonum.inexact->exact x))
(if (cpxnum-real? x) (##denominator (cpxnum-real x)) (error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; floor, ceiling, truncate, round
(define (##floor x)
(define (error) (##trap-check-real 'floor x))
(number-dispatch x (error)
x
x
(##ratnum.floor x)
(##flonum.floor x)
(if (cpxnum-real? x) (##floor (cpxnum-real x)) (error))))
(define (##ceiling x)
(define (error) (##trap-check-real 'ceiling x))
(number-dispatch x (error)
x
x
(##ratnum.ceiling x)
(##flonum.ceiling x)
(if (cpxnum-real? x) (##ceiling (cpxnum-real x)) (error))))
(define (##truncate x)
(define (error) (##trap-check-real 'truncate x))
(number-dispatch x (error)
x
x
(##ratnum.truncate x)
(##flonum.truncate x)
(if (cpxnum-real? x) (##truncate (cpxnum-real x)) (error))))
(define (##round x)
(define (error) (##trap-check-real 'round x))
(number-dispatch x (error)
x
x
(##ratnum.round x)
(##flonum.round x)
(if (cpxnum-real? x) (##round (cpxnum-real x)) (error))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; rationalize
(define (##rationalize x y)
(define (simplest-rational1 x y)
(cond ((##< y x)
(simplest-rational2 y x))
((##not (##< x y))
x)
((##positive? x)
(simplest-rational2 x y))
((##negative? y)
(##- 0 (simplest-rational2 (##- 0 y) (##- 0 x))))
(else
0)))
(define (simplest-rational2 x y)
(let ((fx (##floor x))
(fy (##floor y)))
(cond ((##not (##< fx x))
fx)
((##= fx fy)
(##+ fx
(##/ 1
(simplest-rational2
(##/ 1 (##- y fy))
(##/ 1 (##- x fx))))))
(else
(##+ fx 1)))))
(if (and (##real? x) (##real? y))
(simplest-rational1 (##- x y) (##+ x y))
(##trap-check-real 'rationalize x y)))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; trigonometry and complex numbers
(define (##exp x)
(number-dispatch x (##trap-check-number 'exp x)
(if (##eq? x 0) 1 (##flonum.exp (##flonum.<-fixnum x)))
(##flonum.exp (##flonum.<-bignum x))
(##flonum.exp (##flonum.<-ratnum x))
(##flonum.exp x)
(##make-polar (##exp (cpxnum-real x)) (cpxnum-imag x))))
(define (##log x)
(define (error) (##trap-check-range 'log x))
(define (negative-log x)
(cpxnum-make (##log (##- 0 x)) (inexact-+pi)))
(number-dispatch x (##trap-check-number 'log x)
(if (##fixnum.positive? x)
(if (##eq? x 1) 0 (##flonum.log (##flonum.<-fixnum x)))
(if (##fixnum.= x 0) (error) (negative-log x)))
(if (bignum-positive? x)
(##flonum.log (##flonum.<-bignum x))
(negative-log x))
(if (##positive? (ratnum-numerator x))
(##flonum.log (##flonum.<-ratnum x))
(negative-log x))
(if (##flonum.positive? x)
(##flonum.log x)
(if (##flonum.zero? x) (error) (negative-log x)))
(##make-rectangular (##log (##magnitude x)) (##angle x))))
(define (##sin x)
(number-dispatch x (##trap-check-number 'sin x)
(if (##eq? x 0) 0 (##flonum.sin (##flonum.<-fixnum x)))
(##flonum.sin (##flonum.<-bignum x))
(##flonum.sin (##flonum.<-ratnum x))
(##flonum.sin x)
(##/ (##- (##exp (cpxnum-make (##- 0 (cpxnum-imag x)) (cpxnum-real x)))
(##exp (cpxnum-make (cpxnum-imag x) (##- 0 (cpxnum-real x)))))
(cpxnum-+2i))))
(define (##cos x)
(number-dispatch x (##trap-check-number 'cos x)
(if (##eq? x 0) 1 (##flonum.cos (##flonum.<-fixnum x)))
(##flonum.cos (##flonum.<-bignum x))
(##flonum.cos (##flonum.<-ratnum x))
(##flonum.cos x)
(##/ (##+ (##exp (cpxnum-make (##- 0 (cpxnum-imag x)) (cpxnum-real x)))
(##exp (cpxnum-make (cpxnum-imag x) (##- 0 (cpxnum-real x)))))
2)))
(define (##tan x)
(number-dispatch x (##trap-check-number 'tan x)
(if (##eq? x 0) 0 (##flonum.tan (##flonum.<-fixnum x)))
(##flonum.tan (##flonum.<-bignum x))
(##flonum.tan (##flonum.<-ratnum x))
(##flonum.tan x)
(let ((a (##exp (cpxnum-make (##- 0 (cpxnum-imag x)) (cpxnum-real x))))
(b (##exp (cpxnum-make (cpxnum-imag x) (##- 0 (cpxnum-real x))))))
(let ((c (##/ (##- a b) (##+ a b))))
(##make-rectangular (##imag-part c) (##- 0 (##real-part c)))))))
(define (##asin x)
(define (safe-case x)
(##* (cpxnum--i)
(##log (##+ (##* (cpxnum-+i) x)
(##sqrt (##- 1 (##* x x)))))))
(define (unsafe-case x)
(##- 0 (safe-case (##- 0 x))))
(define (real-case x)
(cond ((##< x -1)
(unsafe-case x))
((##< 1 x)
(safe-case x))
(else
(##flonum.asin (##exact->inexact x)))))
(number-dispatch x (##trap-check-number 'asin x)
(if (##eq? x 0) 0 (real-case x))
(real-case x)
(real-case x)
(real-case x)
(let ((imag (cpxnum-imag x)))
(if (or (##positive? imag)
(and (flonum-zero? imag) (##negative? (cpxnum-real x))))
(unsafe-case x)
(safe-case x)))))
(define (##acos x)
(define (complex-case x)
(##* (cpxnum--i)
(##log (##+ x
(##* (cpxnum-+i) (##sqrt (##- 1 (##* x x))))))))
(define (real-case x)
(if (or (##< x -1) (##< 1 x))
(complex-case x)
(##flonum.acos (##exact->inexact x))))
(number-dispatch x (##trap-check-number 'acos x)
(if (##eq? x 0) 0 (real-case x))
(real-case x)
(real-case x)
(real-case x)
(complex-case x)))
(define (##atan x)
(number-dispatch x (##trap-check-number 'atan x)
(if (##eq? x 0) 0 (##flonum.atan (##flonum.<-fixnum x)))
(##flonum.atan (##flonum.<-bignum x))
(##flonum.atan (##flonum.<-ratnum x))
(##flonum.atan x)
(let ((a (cpxnum-make (##- 0 (cpxnum-imag x)) (cpxnum-real x))))
(##/ (##- (##log (##+ a 1)) (##log (##- 1 a)))
(cpxnum-+2i)))))
(define (##atan2 y x)
(if (and (##real? x) (##real? y))
(let ((x (##exact->inexact x)) (y (##exact->inexact y)))
(cond ((##flonum.positive? x)
(##flonum.atan (##flonum./ y x)))
((##flonum.negative? y)
(if (##flonum.zero? x)
(inexact--pi/2)
(##flonum.+ (##flonum.atan (##flonum./ y x)) (inexact--pi))))
(else
(if (##flonum.zero? x)
(inexact-+pi/2)
(##flonum.+ (##flonum.atan (##flonum./ y x)) (inexact-+pi))))))
(##trap-check-real 'atan y x)))
(define (##sqrt x)
(define (exact-int-sqrt x)
(cond ((##eq? x 0)
0)
((##negative? x)
(cpxnum-make 0 (exact-int-sqrt (##- 0 x))))
(else
(let ((y (##exact-int.root x 2)))
(if (##= x (##* y y))
y
(##flonum.sqrt (##exact->inexact x)))))))
(number-dispatch x (##trap-check-number 'sqrt x)
(exact-int-sqrt x)
(exact-int-sqrt x)
(##/ (exact-int-sqrt (ratnum-numerator x))
(exact-int-sqrt (ratnum-denominator x)))
(if (##flonum.negative? x)
(cpxnum-make 0 (##flonum.sqrt (##flonum.- (inexact-0) x)))
(##flonum.sqrt x))
(##make-polar (##sqrt (##magnitude x)) (##/ (##angle x) 2))))
(define (##expt x y)
(define (error) (##trap-check-number 'expt x y))
(define (general-expt x y)
(##exp (##* (##log x) y)))
(define (exact-int-expt x y)
(cond ((##eq? y 0)
1)
((or (##zero? x) (##= x 1))
x)
(else
(let loop ((x x) (y y) (result 1))
(if (##eq? y 1)
(##* x result)
(loop (##* x x)
(##quotient y 2)
(if (##odd? y) (##* x result) result)))))))
(if (##complex? x)
(cond ((exact-int? y)
(if (##negative? y)
(##/ 1 (exact-int-expt x (##- 0 y)))
(exact-int-expt x y)))
((##complex? y)
(cond ((##zero? y) (inexact-+1))
((##zero? x) (if (##eq? x 0) 0 (inexact-0)))
(else (general-expt x y))))
(else
(error)))
(error)))
(define (##make-rectangular x y)
(if (and (##real? x) (##real? y))
(if (##eq? y 0)
x
(cpxnum-make (##real-part x) (##real-part y)))
(##trap-check-real 'make-rectangular x y)))
(define (##make-polar x y)
(if (and (##real? x) (##real? y))
(let ((x* (##real-part x)) (y* (##real-part y)))
(##make-rectangular (##* x* (##cos y*)) (##* x* (##sin y*))))
(##trap-check-real 'make-polar x y)))
(define (##real-part x)
(number-dispatch x (##trap-check-number 'real-part x)
x x x x (cpxnum-real x)))
(define (##imag-part x)
(number-dispatch x (##trap-check-number 'imag-part x)
0 0 0 0 (cpxnum-imag x)))
(define (##magnitude x)
(number-dispatch x (##trap-check-number 'magnitude x)
(if (##fixnum.negative? x) (##bignum.-/fixnum-fixnum 0 x) x)
(if (bignum-negative? x) (##bignum.-/fixnum-bignum 0 x) x)
(if (##negative? (ratnum-numerator x))
(ratnum-make (##- 0 (ratnum-numerator x)) (ratnum-denominator x))
x)
(##flonum.abs x)
(let ((r (##abs (##real-part x))) (i (##abs (##imag-part x))))
(define (complex-magn a b)
(if (##zero? b)
b
(let ((c (##/ a b)))
(##* b (##sqrt (##+ (##* c c) 1))))))
(if (##< r i) (complex-magn r i) (complex-magn i r)))))
(define (##angle x)
(number-dispatch x (##trap-check-number 'angle x)
(if (##fixnum.negative? x) (inexact-+pi) 0)
(if (bignum-negative? x) (inexact-+pi) 0)
(if (##negative? (ratnum-numerator x)) (inexact-+pi) 0)
(if (##flonum.negative? x) (inexact-+pi) (inexact-0))
(if (##zero? x)
(inexact-0)
(##atan2 (cpxnum-imag x) (cpxnum-real x)))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; exact->inexact, inexact->exact
(define (##exact->inexact x)
(number-dispatch x (##trap-check-number 'exact->inexact x)
(##flonum.<-fixnum x)
(##flonum.<-bignum x)
(##flonum.<-ratnum x)
x
(##make-rectangular (##exact->inexact (cpxnum-real x))
(##exact->inexact (cpxnum-imag x)))))
(define (##inexact->exact x)
(number-dispatch x (##trap-check-number 'inexact->exact x)
x
x
x
(##flonum.inexact->exact x)
(##make-rectangular (##inexact->exact (cpxnum-real x))
(##inexact->exact (cpxnum-imag x)))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; number->string, string->number
(define (##number->string x rad)
(define (non-cpxnum->string x)
(cond ((exact-int? x)
(##exact-int.number->string x rad))
((##ratnum? x)
(##string-append (##exact-int.number->string (ratnum-numerator x) rad)
"/"
(##exact-int.number->string (ratnum-denominator x) rad)))
((##flonum? x)
(##flonum.number->string x))
(else
(##trap-check-number 'number->string x rad))))
(if (or (##eq? rad 2)
(##eq? rad 8)
(##eq? rad 10)
(##eq? rad 16))
(if (##cpxnum? x)
(let* ((real (cpxnum-real x))
(real-str (if (##eq? real 0) "" (non-cpxnum->string real))))
(let ((imag (cpxnum-imag x)))
(cond ((##eq? imag 1)
(##string-append real-str "+i"))
((##eq? imag -1)
(##string-append real-str "-i"))
((##negative? imag)
(##string-append real-str (non-cpxnum->string imag) "i"))
(else
(##string-append real-str "+" (non-cpxnum->string imag) "i")))))
(non-cpxnum->string x))
(##trap-check-range 'number->string x rad)))
(define (##exact-int.number->string x rad)
(if (##fixnum? x)
(##fixnum.number->string x rad)
(##bignum.number->string x rad)))
(define (##flonum.number->string x)
(define (num->str x)
(let ((z (##flonum.->exact-exponential-format x)))
(##flonum.printout (##car z) (##cdr z))))
(cond ((##flonum.zero? x)
"0.")
((##flonum.negative? x)
(##string-append "-" (num->str (##flonum.abs x))))
(else
(num->str x))))
(##define-macro (two) 2)
(##define-macro (ten) 10)
(##define-macro (ten-minus-1) 9)
(define (##flonum.printout m e)
(define (done h k d)
(let ((str (##exact-int.number->string d (ten))))
(cond ((and (##fixnum.< h -1)
(or ; (##fixnum.< -5 h)
(##fixnum.< (##fixnum.- 0 (flonum-max-digits)) k)))
(##string-append "."
(##make-string (##fixnum.- -1 h) #\0)
str))
((and (##fixnum.< 0 k)
(or ; (##fixnum.< k 3)
(##fixnum.< h (flonum-max-digits))))
(##string-append str
(##make-string k #\0)
"."))
((and (##fixnum.< -2 h) (##fixnum.< k 1))
(let ((n (##fixnum.+ h 1)))
(##string-append (##substring str 0 n)
"."
(##substring str n (##string-length str)))))
(else
(##string-append (##substring str 0 1)
"."
(##substring str 1 (##string-length str))
"e"
(##exact-int.number->string h (ten)))))))
(define (fixup-loop1 k r s ceiling-s-div-ten m- m+)
(if (##< r ceiling-s-div-ten)
(fixup-loop1 (##fixnum.- k 1)
(##* r (ten))
s
ceiling-s-div-ten
(##* m- (ten))
(##* m+ (ten)))
(let fixup-loop2 ((k k) (r r) (s s) (m- m-) (m+ m+))
(if (##not (##< (##+ (##* r 2) m+) (##* s 2)))
(fixup-loop2 (##fixnum.+ k 1) r (##* s (ten)) m- m+)
(let ((h (##fixnum.- k 1)))
(let ((ur (##exact-int.div (##* r (ten)) s)))
(let loop ((k (##fixnum.- k 1))
(u (##car ur))
(r (##cdr ur))
(m- (##* m- (ten)))
(m+ (##* m+ (ten)))
(d 0))
(let ((r*2 (##* r 2)) (s*2 (##* s 2)))
(cond ((##< r*2 m-)
(if (##< (##- s*2 m+) r*2)
(if (##not (##< s r*2))
(done h k (##+ d u))
(done h k (##+ d (##fixnum.+ u 1))))
(done h k (##+ d u))))
((##< (##- s*2 m+) r*2)
(done h k (##+ d (##fixnum.+ u 1))))
(else
(let ((ur (##exact-int.div (##* r (ten)) s)))
(loop (##fixnum.- k 1)
(##car ur)
(##cdr ur)
(##* m- (ten))
(##* m+ (ten))
(##* (##+ d u) (ten))))))))))))))
(define (fixup r s m-)
(if (##= m (flonum-+m-min))
(let ((r* (##* r (two)))
(s* (##* s (two)))
(m+ (##* m- (two))))
(fixup-loop1 0 r* s* (##quotient (##+ s* (ten-minus-1)) (ten)) m- m+))
(fixup-loop1 0 r s (##quotient (##+ s (ten-minus-1)) (ten)) m- m-)))
(if (##fixnum.negative? e)
(fixup m (##expt (two) (##fixnum.- 0 e)) 1)
(let ((two-to-the-e (##expt (two) e)))
(fixup (##* m two-to-the-e) 1 two-to-the-e))))
(define (##string->number s rad)
(define (make-real e n r p) ; Note: this algorithm does not satisfy the
(let ((x (##* n (##expt r p)))) ; accuracy required by the IEEE standard
(if (##eq? e 'E) x (##exact->inexact x))))
(define (make-rec a b)
(##make-rectangular a b))
(define (make-pol a b)
(##make-polar a b))
(define (ex e x)
(if (##eq? e 'I) (##exact->inexact x) x))
(define (end s i x)
(if (##eq? i (##string-length s)) x #f))
(define (radix-prefix s i)
(if (##fixnum.< (##fixnum.+ i 1) (##string-length s))
(if (##char=? (##string-ref s i) #\#)
(let ((c (##string-ref s (##fixnum.+ i 1))))
(cond ((or (##char=? c #\b) (##char=? c #\B)) 2)
((or (##char=? c #\o) (##char=? c #\O)) 8)
((or (##char=? c #\d) (##char=? c #\D)) 10)
((or (##char=? c #\x) (##char=? c #\X)) 16)
(else #f)))
#f)
#f))
(define (exactness-prefix s i)
(if (##fixnum.< (##fixnum.+ i 1) (##string-length s))
(if (##char=? (##string-ref s i) #\#)
(let ((c (##string-ref s (##fixnum.+ i 1))))
(cond ((or (##char=? c #\i) (##char=? c #\I)) 'I)
((or (##char=? c #\e) (##char=? c #\E)) 'E)
(else #f)))
#f)
#f))
(define (sign s i)
(if (##fixnum.< i (##string-length s))
(let ((c (##string-ref s i)))
(cond ((##char=? c #\+) '+)
((##char=? c #\-) '-)
(else #f)))
#f))
(define (imaginary s i)
(if (##fixnum.< i (##string-length s))
(let ((c (##string-ref s i)))
(or (##char=? c #\i) (##char=? c #\I)))
#f))
(define (polar s i)
(if (##fixnum.< i (##string-length s))
(##char=? (##string-ref s i) #\@)
#f))
(define (ratio s i)
(if (##fixnum.< i (##string-length s))
(##char=? (##string-ref s i) #\/)
#f))
(define (exponent s i)
(if (##fixnum.< i (##string-length s))
(let ((c (##string-ref s i)))
(cond ((or (##char=? c #\e) (##char=? c #\E)) 'E)
((or (##char=? c #\s) (##char=? c #\S)) 'S)
((or (##char=? c #\f) (##char=? c #\F)) 'F)
((or (##char=? c #\d) (##char=? c #\D)) 'D)
((or (##char=? c #\l) (##char=? c #\L)) 'L)
(else #f)))
#f))
(define (digit c r)
(let ((d (cond ((##not (or (##char<? c #\0) (##char<? #\9 c)))
(##fixnum.- (##char->integer c) 48))
((##not (or (##char<? c #\a) (##char<? #\z c)))
(##fixnum.- (##char->integer c) 87))
((##not (or (##char<? c #\A) (##char<? #\Z c)))
(##fixnum.- (##char->integer c) 55))
(else
#f))))
(if (and d (##fixnum.< d r)) d #f)))
(define (prefix s i r cont)
(let ((e1 (exactness-prefix s i)))
(if e1
(let ((r1 (radix-prefix s (##fixnum.+ i 2))))
(if r1
(cont s (##fixnum.+ i 4) r1 e1)
(cont s (##fixnum.+ i 2) r e1)))
(let ((r2 (radix-prefix s i)))
(if r2
(let ((e2 (exactness-prefix s (##fixnum.+ i 2))))
(if e2
(cont s (##fixnum.+ i 4) r2 e2)
(cont s (##fixnum.+ i 2) r2 #f)))
(cont s i r #f))))))
(define (num s i r)
(prefix s i r complex))
(define (complex s i r e)
(let ((+/- (sign s i)))
(ucomplex s (if +/- (##fixnum.+ i 1) i) r e +/-)))
(define (ucomplex s i r e +/-)
(if (and +/- (imaginary s i))
(end s (##fixnum.+ i 1)
(make-rec (ex e 0) (ex e (if (##eq? +/- '-) -1 1))))
(ureal s i r e +/- #f
(lambda (s i r e +/- dummy x)
(let ((y (if (##eq? +/- '-) (##- 0 x) x)))
(cond ((and +/- (imaginary s i))
(end s (##fixnum.+ i 1) (make-rec (ex e 0) y)))
((polar s i)
(let ((+/-2 (sign s (##fixnum.+ i 1))))
(ureal s (##fixnum.+ i (if +/-2 2 1)) r e +/-2 y
(lambda (s i r e +/-2 y z)
(end s i
(make-pol y (if (##eq? +/-2 '-) (##- 0 z) z)))))))
(else
(let ((+/-2 (sign s i)))
(if +/-2
(if (imaginary s (##fixnum.+ i 1))
(end s (##fixnum.+ i 2)
(make-rec y (ex e (if (##eq? +/-2 '-) -1 1))))
(ureal s (##fixnum.+ i 1) r e +/-2 y
(lambda (s i r e +/-2 y z)
(and (imaginary s i)
(end s (##fixnum.+ i 1)
(make-rec y (if (##eq? +/-2 '-) (##- 0 z) z)))))))
(end s i y))))))))))
(define (ureal s i r e +/- x cont)
(uinteger s i r e +/- x cont (##eq? r 10)
(lambda (s i r e +/- x cont ex? n p)
(if p ; decimal point or exponent?
(cont s i r e +/- x (make-real e n r p))
(if (ratio s i)
(uinteger s (##fixnum.+ i 1) r e +/- x cont #f
(lambda (s i r e +/- x cont ex2? n2 p2)
(let ((y (##/ n n2)))
(cont s i r e +/- x (ex (or e (if (and ex? ex2?) #f 'I)) y)))))
(cont s i r e +/- x (ex (or e (if ex? #f 'I)) n)))))))
(define (uinteger s i r a1 a2 a3 a4 decimal? cont)
(let loop1 ((i i) (state 0) (n 0) (p #f))
(define (suffix)
(if (##eq? state 0)
#f
(let ((mark (exponent s i)))
(if (and mark decimal?)
(let ((+/- (sign s (##fixnum.+ i 1))) (p (or p 0)))
(let loop2 ((i (##fixnum.+ i (if +/- 2 1))) (j #f))
(if (and (##fixnum.< i (##string-length s))
(digit (##string-ref s i) 10))
(loop2 (##fixnum.+ i 1)
(##+ (##* (or j 0) 10)
(digit (##string-ref s i) 10)))
(and j (cont s i r a1 a2 a3 a4 #f n
(##+ p (if (##eq? +/- '-) (##- 0 j) j)))))))
(cont s i r a1 a2 a3 a4 (##not (or (##eq? state 2) p)) n p)))))
(if (##fixnum.< i (##string-length s))
(let ((c (##string-ref s i)))
(if (and (##char=? c #\.) decimal? (##not p))
(loop1 (##fixnum.+ i 1) state n 0)
(if (and (##char=? c #\#) (##fixnum.< 0 state))
(loop1 (##fixnum.+ i 1) 2 (##* n r) (and p (##fixnum.- p 1)))
(if (##fixnum.< state 2)
(let ((d (digit c r)))
(if d
(loop1 (##fixnum.+ i 1)
1
(##+ (##* n r) d)
(and p (##fixnum.- p 1)))
(suffix)))
(suffix)))))
(suffix))))
(if (or (##eq? rad 2)
(##eq? rad 8)
(##eq? rad 10)
(##eq? rad 16))
(num s 0 rad)
(##trap-check-range 'string->number s rad)))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; ##logior, ##logxor, ##logand, ##lognot, ##ash
(define-nary0 (##fixnum.logior x y) 0 x (##fixnum.logior x y) no-touch)
(define-nary0 (##fixnum.logxor x y) 0 x (##fixnum.logxor x y) no-touch)
(define-nary0 (##fixnum.logand x y) -1 x (##fixnum.logand x y) no-touch)
(define-system (##fixnum.lognot x) (##fixnum.- -1 x))
(define-system (##fixnum.ash x y))
(define-system (##fixnum.lsh x y))
(define-nary0 (##logior x y) 0 x (####logior x y) touch-vars)
(define-nary0 (##logxor x y) 0 x (####logxor x y) touch-vars)
(define-nary0 (##logand x y) -1 x (####logand x y) touch-vars)
(define (##lognot x) (touch-vars (x) (####lognot x)))
(define (##ash x y) (touch-vars (x y) (####ash x y)))
(define (####logior x y)
(define (otherwise x y)
(##trap-check-integer '##logior x y))
(cond ((##fixnum? y)
(cond ((##fixnum? x)
(##fixnum.logior x y))
((##bignum? x)
(##bignum.logior/bignum-fixnum x y))
(else
(otherwise x y))))
((##bignum? y)
(cond ((##fixnum? x)
(##bignum.logior/bignum-fixnum y x))
((##bignum? x)
(##bignum.logior x y))
(else
(otherwise x y))))
(else
(otherwise x y))))
(define (####logxor x y)
(define (otherwise x y)
(##trap-check-integer '##logxor x y))
(cond ((##fixnum? y)
(cond ((##fixnum? x)
(##fixnum.logxor x y))
((##bignum? x)
(##bignum.logxor/bignum-fixnum x y))
(else
(otherwise x y))))
((##bignum? y)
(cond ((##fixnum? x)
(##bignum.logxor/bignum-fixnum y x))
((##bignum? x)
(##bignum.logxor x y))
(else
(otherwise x y))))
(else
(otherwise x y))))
(define (####logand x y)
(define (otherwise x y)
(##trap-check-integer '##logand x y))
(cond ((##fixnum? y)
(cond ((##fixnum? x)
(##fixnum.logand x y))
((##bignum? x)
(##bignum.logand/bignum-fixnum x y))
(else
(otherwise x y))))
((##bignum? y)
(cond ((##fixnum? x)
(##bignum.logand/bignum-fixnum y x))
((##bignum? x)
(##bignum.logand x y))
(else
(otherwise x y))))
(else
(otherwise x y))))
(define (####lognot x)
(define (otherwise x)
(##trap-check-integer '##lognot x))
(cond ((##fixnum? x)
(##fixnum.lognot x))
((##bignum? x)
(##bignum.-/fixnum-bignum -1 x))
(else
(otherwise x))))
(define (####ash x y)
(define (otherwise x y)
(##trap-check-integer '##ash x y))
(cond ((##fixnum? y)
(cond ((##fixnum? x)
(##bignum.ash/fixnum-fixnum x y))
((##bignum? x)
(##bignum.ash/bignum-fixnum x y))
(else
(otherwise x y))))
((##bignum? y)
(cond ((##fixnum? x)
(##bignum.ash/fixnum-bignum x y))
((##bignum? x)
(##bignum.ash x y))
(else
(otherwise x y))))
(else
(otherwise x y))))
(define (##bignum.logior/bignum-fixnum x y)
(##bignum.logior x (##bignum.<-fixnum y)))
(define (##bignum.logxor/bignum-fixnum x y)
(##bignum.logxor x (##bignum.<-fixnum y)))
(define (##bignum.logand/bignum-fixnum x y)
(##bignum.logand x (##bignum.<-fixnum y)))
(define (##bignum.ash/fixnum-fixnum x y)
(##bignum.ash (##bignum.<-fixnum x) (##bignum.<-fixnum y)))
(define (##bignum.ash/bignum-fixnum x y)
(##bignum.ash x (##bignum.<-fixnum y)))
(define (##bignum.ash/fixnum-bignum x y)
(##bignum.ash (##bignum.<-fixnum x) y))
(define (##bignum.logior x y)
(##trap-unimplemented '##logior x y))
(define (##bignum.logxor x y)
(##trap-unimplemented '##logxor x y))
(define (##bignum.logand x y)
(##trap-unimplemented '##logand x y))
(define (##bignum.ash x y)
(##trap-unimplemented '##ash x y))
; other utilities
(define (##exact-int.width x)
(if (##fixnum? x)
(##fixnum.width x)
(##bignum.width x)))
(define (##fixnum.width x)
(if (##fixnum.negative? x)
(let loop1 ((w 0) (x x))
(if (##fixnum.< x -1) (loop1 (##fixnum.+ w 1) (##fixnum.ash x -1)) w))
(let loop2 ((w 0) (x x))
(if (##fixnum.< 0 x) (loop2 (##fixnum.+ w 1) (##fixnum.ash x -1)) w))))
(define (##bignum.width x)
(if (bignum-negative? x)
(##bignum.width (##- -1 x)) ; lazy...
(let ((len (bignum-length x)))
(##fixnum.+ (##fixnum.* (##fixnum.- len 2) (radix-width))
(##fixnum.width (bignum-digit-ref x (##fixnum.- len 1)))))))
(define (##exact-int.root x y)
(let loop ((g (##expt 2
(##quotient (##+ (##exact-int.width x) (##- y 1)) y))))
(let ((a (##expt g (##- y 1))))
(let ((b (##* a y)))
(let ((c (##* a (##- y 1))))
(let ((d (##quotient (##+ x (##* g c)) b)))
(if (##< d g) (loop d) g)))))))
(define (##exact-int.div x y)
(define (div x y)
(let ((z (##bignum.div x y)))
(##set-car! z (##bignum.normalize (##car z)))
(##set-cdr! z (##bignum.normalize (##cdr z)))
z))
(if (##fixnum? x)
(if (##fixnum? y)
(##cons (##fixnum.quotient x y) (##fixnum.remainder x y))
(div (##bignum.<-fixnum x) y))
(if (##fixnum? y)
(div x (##bignum.<-fixnum y))
(div x y))))
;------------------------------------------------------------------------------
; Fixnum operations
; -----------------
(define-system (##fixnum.zero? x)
(##eq? x 0))
(define-system (##fixnum.positive? x)
(##fixnum.< 0 x))
(define-system (##fixnum.negative? x)
(##fixnum.< x 0))
(define-system (##fixnum.odd? x)
(##eq? (##fixnum.modulo x 2) 1))
(define-system (##fixnum.even? x)
(##eq? (##fixnum.modulo x 2) 0))
(define-nary0-boolean (##fixnum.= x y)
(##eq? x y) no-check no-touch)
(define-nary0-boolean (##fixnum.< x y)
(##fixnum.< x y) no-check no-touch)
(define-nary0-boolean (##fixnum.> x y)
(##fixnum.< y x) no-check no-touch)
(define-nary0-boolean (##fixnum.<= x y)
(##not (##fixnum.< y x)) no-check no-touch)
(define-nary0-boolean (##fixnum.>= x y)
(##not (##fixnum.< x y)) no-check no-touch)
(define-nary0 (##fixnum.+ x y) 0 x (##fixnum.+ x y) no-touch)
(define-nary0 (##fixnum.* x y) 1 x (##fixnum.* x y) no-touch)
(define-nary1 (##fixnum.- x y) (##fixnum.- 0 x) (##fixnum.- x y) no-touch)
(define-system (##fixnum.quotient x y))
(define-system (##fixnum.remainder x y)
(##fixnum.- x (##fixnum.* (##fixnum.quotient x y) y)))
(define-system (##fixnum.modulo x y)
(let ((r (##fixnum.remainder x y)))
(if (##eq? r 0)
0
(if (##fixnum.< x 0)
(if (##fixnum.< y 0) r (##fixnum.+ r y))
(if (##fixnum.< y 0) (##fixnum.+ r y) r)))))
(define (##fixnum.number->string n rad)
(define (loop k n i)
(let ((x (##fixnum.quotient n rad)))
(let ((s (if (##eq? x 0)
(##make-string (##fixnum.+ i k) #\space)
(loop k x (##fixnum.+ i 1)))))
(##string-set! s
(##fixnum.- (##string-length s) i)
(##string-ref "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
(##fixnum.- 0 (##fixnum.remainder n rad)))))))
(if (##fixnum.< n 0)
(##string-set! (loop 1 n 1) 0 #\-)
(loop 0 (##fixnum.- 0 n) 1)))
;------------------------------------------------------------------------------
; Bignum operations
; -----------------
; Bignums are represented with 'word' vectors:
;
; assuming that the bignum 'n' is represented by the word vector 'v' of
; length 'l', we have
;
; l-2
; -----
; \ i
; n = (v[0]*2-1) * > v[i+1] * radix
; /
; -----
; i = 0
;
; note: v[0] = 0 if number is negative, v[0] = 1 if number is positive.
;
; 'radix' must be less than or equal to sqrt(max fixnum)+1. This guarantees
; that the result of an arithmetic operation on bignum digits will be a fixnum
; (this includes the product of two digits).
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Bignum comparison
(define (##bignum.= x y)
(if (##not (##eq? (bignum-sign x) (bignum-sign y)))
#f
(let ((lx (bignum-length x)))
(if (##not (##eq? lx (bignum-length y)))
#f
(let loop ((i (##fixnum.- lx 1)))
(if (##fixnum.< 0 i)
(if (##not (##eq? (bignum-digit-ref x i)
(bignum-digit-ref y i)))
#f
(loop (##fixnum.- i 1)))
#t))))))
(define (##bignum.< x y)
(if (##not (##eq? (bignum-sign x) (bignum-sign y)))
(bignum-negative? x)
(let ((lx (bignum-length x))
(ly (bignum-length y)))
(cond ((##fixnum.< lx ly)
(bignum-positive? x))
((##fixnum.< ly lx)
(bignum-negative? x))
(else
(let loop ((i (##fixnum.- lx 1)))
(if (##fixnum.< 0 i)
(let ((dx (bignum-digit-ref x i))
(dy (bignum-digit-ref y i)))
(cond ((##fixnum.< dx dy) (bignum-positive? x))
((##fixnum.< dy dx) (bignum-negative? x))
(else (loop (##fixnum.- i 1)))))
#f)))))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Operations on fixnums that might result in a bignum
(define (##bignum.+/fixnum-fixnum x y)
(if (##fixnum.< x 0)
(if (##fixnum.< y 0)
(let ((r (##fixnum.+ x y)))
(if (##fixnum.< r 0)
r
(##bignum.+/bignum-fixnum ##bignum.2*min-fixnum r)))
(##fixnum.+ x y))
(if (##fixnum.< y 0)
(##fixnum.+ x y)
(let ((r (##fixnum.+ x y)))
(if (##fixnum.< r 0)
(##bignum.-/fixnum-bignum r ##bignum.2*min-fixnum)
r)))))
(define (##bignum.-/fixnum-fixnum x y)
(if (##fixnum.< x 0)
(if (##fixnum.< y 0)
(##fixnum.- x y)
(let ((r (##fixnum.- x y)))
(if (##fixnum.< r 0)
r
(##bignum.+/bignum-fixnum ##bignum.2*min-fixnum r))))
(if (##fixnum.< y 0)
(let ((r (##fixnum.- x y)))
(if (##fixnum.< r 0)
(##bignum.-/fixnum-bignum r ##bignum.2*min-fixnum)
r))
(##fixnum.- x y))))
(define (##bignum.*/fixnum-fixnum x y)
(cond ((and (##not (##fixnum.< x (minus-radix))) (##fixnum.< x (radix))
(##fixnum.< (minus-radix) y) (##not (##fixnum.< (radix) y)))
(##fixnum.* x y))
((or (##fixnum.= x 0) (##fixnum.= y 0))
0)
((##fixnum.= x 1)
y)
((##fixnum.= y 1)
x)
(else
(##bignum.* (##bignum.<-fixnum x) (##bignum.<-fixnum y)))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Mixed representation operations
(define (##bignum.+/bignum-fixnum x y)
(##bignum.+ x (##bignum.<-fixnum y)))
(define (##bignum.-/bignum-fixnum x y)
(##bignum.- x (##bignum.<-fixnum y)))
(define (##bignum.-/fixnum-bignum x y)
(##bignum.- (##bignum.<-fixnum x) y))
(define (##bignum.*/bignum-fixnum x y)
(cond ((##fixnum.= y 0)
0)
((##fixnum.= y 1)
x)
(else
(##bignum.* x (##bignum.<-fixnum y)))))
(define (##bignum.quotient/bignum-fixnum x y)
(##bignum.quotient x (##bignum.<-fixnum y)))
(define (##bignum.quotient/fixnum-bignum x y)
(##bignum.quotient (##bignum.<-fixnum x) y))
(define (##bignum.remainder/bignum-fixnum x y)
(##bignum.remainder x (##bignum.<-fixnum y)))
(define (##bignum.remainder/fixnum-bignum x y)
(##bignum.remainder (##bignum.<-fixnum x) y))
(define (##bignum.modulo/bignum-fixnum x y)
(##bignum.modulo x (##bignum.<-fixnum y)))
(define (##bignum.modulo/fixnum-bignum x y)
(##bignum.modulo (##bignum.<-fixnum x) y))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Operations where arguments are in bignum format
; Addition and substraction
(define (##bignum.+ x y)
(##bignum.normalize (##bignum.sum x y (bignum-sign x) (bignum-sign y))))
(define (##bignum.- x y)
(##bignum.normalize (##bignum.sum x y (bignum-sign x) (bignum-sign* y))))
(define (##bignum.sum x y sign-x sign-y)
(define (adjust-sign! x s)
(if (##eq? (bignum-sign x) s)
(bignum-set-positive! x)
(bignum-set-negative! x))
x)
(cond ((##eq? sign-x sign-y) ; same sign
(adjust-sign! (##bignum.add x y) sign-x))
((##fixnum.< (bignum-length x) (bignum-length y))
(adjust-sign! (##bignum.sub y x) sign-y))
(else
(adjust-sign! (##bignum.sub x y) sign-x))))
(define (##bignum.add x y)
(define (add x y lx ly)
(let ((r (bignum-make (##fixnum.+ lx 1))))
(bignum-set-positive! r)
(let loop1 ((i 1) (c 0)) ; add digits in y
(if (##fixnum.< i ly)
(let ((w (##fixnum.+ (##fixnum.+ (bignum-digit-ref x i)
(bignum-digit-ref y i))
c)))
(if (##fixnum.< w (radix))
(begin
(bignum-digit-set! r i w)
(loop1 (##fixnum.+ i 1) 0))
(begin
(bignum-digit-set! r i (##fixnum.- w (radix)))
(loop1 (##fixnum.+ i 1) 1))))
(let loop2 ((i i) (c c)) ; propagate carry
(if (##fixnum.< i lx)
(let ((w (##fixnum.+ (bignum-digit-ref x i) c)))
(if (##fixnum.< w (radix))
(begin
(bignum-digit-set! r i w)
(loop2 (##fixnum.+ i 1) 0))
(begin
(bignum-digit-set! r i (##fixnum.- w (radix)))
(loop2 (##fixnum.+ i 1) 1))))
(if (##eq? c 0)
(bignum-shrink! r lx)
(bignum-digit-set! r lx c))))))
r))
(let ((lx (bignum-length x))
(ly (bignum-length y)))
(if (##fixnum.< lx ly)
(add y x ly lx)
(add x y lx ly))))
(define (##bignum.sub x y)
(define (complement! r)
(let ((lr (bignum-length r)))
(let loop ((i 1) (c 0))
(if (##fixnum.< i lr)
(let ((w (##fixnum.+ (bignum-digit-ref r i) c)))
(if (##fixnum.< 0 w)
(begin
(bignum-digit-set! r i (##fixnum.- (radix) w))
(loop (##fixnum.+ i 1) 1))
(begin
(bignum-digit-set! r i 0)
(loop (##fixnum.+ i 1) 0))))))))
(define (sub x y lx ly)
(let ((r (bignum-make lx)))
(let loop1 ((i 1) (b 0)) ; substract digits in y
(if (##fixnum.< i ly)
(let ((w (##fixnum.- (##fixnum.- (bignum-digit-ref x i)
(bignum-digit-ref y i))
b)))
(if (##fixnum.< w 0)
(begin
(bignum-digit-set! r i (##fixnum.+ w (radix)))
(loop1 (##fixnum.+ i 1) 1))
(begin
(bignum-digit-set! r i w)
(loop1 (##fixnum.+ i 1) 0))))
(let loop2 ((i i) (b b)) ; propagate borrow
(if (##fixnum.< i lx)
(let ((w (##fixnum.- (bignum-digit-ref x i) b)))
(if (##fixnum.< w 0)
(begin
(bignum-digit-set! r i (##fixnum.+ w (radix)))
(loop2 (##fixnum.+ i 1) 1))
(begin
(bignum-digit-set! r i w)
(loop2 (##fixnum.+ i 1) 0))))
(if (##eq? b 0)
(bignum-set-positive! r)
(begin
(bignum-set-negative! r)
(complement! r)))))))
(##bignum.remove-leading-0s! r)
r))
(sub x y (bignum-length x) (bignum-length y)))
; Multiplication
(define (##bignum.* x y)
(define (mul x y lx ly)
(let ((r (bignum-make (##fixnum.- (##fixnum.+ lx ly) 1))))
(if (##eq? (bignum-sign x) (bignum-sign y))
(bignum-set-positive! r)
(bignum-set-negative! r))
(let loop1 ((j 1)) ; for each digit in y
(if (##fixnum.< j ly)
(let ((d (bignum-digit-ref y j)))
(let loop2 ((i 1) (k j) (c 0)) ; multiply and add
(if (##fixnum.< i lx)
(let ((w (##fixnum.+ (##fixnum.+ (bignum-digit-ref r k) c)
(##fixnum.* (bignum-digit-ref x i) d))))
(bignum-digit-set! r k (##fixnum.modulo w (radix)))
(loop2 (##fixnum.+ i 1)
(##fixnum.+ k 1)
(##fixnum.quotient w (radix))))
(begin
(bignum-digit-set! r k c)
(loop1 (##fixnum.+ j 1))))))))
(##bignum.remove-leading-0s! r)
r))
(##bignum.normalize (mul x y (bignum-length x) (bignum-length y))))
; Division
(define (##bignum.quotient x y)
(##bignum.normalize (##car (##bignum.div x y))))
(define (##bignum.remainder x y)
(##bignum.normalize (##cdr (##bignum.div x y))))
(define (##bignum.modulo x y)
(let ((r (##cdr (##bignum.div x y))))
(if (bignum-zero? r)
0
(if (bignum-negative? x)
(if (bignum-negative? y) (##bignum.normalize r) (##bignum.+ r y))
(if (bignum-negative? y) (##bignum.+ r y) (##bignum.normalize r))))))
(define (##bignum.div x y)
(define (single-digit-divisor-div x y lx ly r)
; simple algo for single digit divisor
(let ((d (bignum-digit-ref y 1)))
(let loop1 ((i (##fixnum.- lx 1)) (k 0))
(if (##fixnum.< 0 i)
(let ((w (##fixnum.+ (##fixnum.* k (radix)) (bignum-digit-ref x i))))
(bignum-digit-set! r i (##fixnum.quotient w d))
(loop1 (##fixnum.- i 1) (##fixnum.remainder w d)))
(begin
(##bignum.remove-leading-0s! r)
(##cons r (##bignum.<-fixnum
(if (bignum-negative? x) (##fixnum.- 0 k) k))))))))
(define (multi-digit-divisor-div x y lx ly r)
; general algo from knuth
; STEP 1: normalize x and y
(let loop2 ((shift 1)
(n (##fixnum.* (bignum-digit-ref y (##fixnum.- ly 1)) 2)))
(if (##fixnum.< n (radix))
(loop2 (##fixnum.* shift 2) (##fixnum.* n 2))
(let ((nx (bignum-make (##fixnum.+ lx 1)))
(ny (bignum-make ly)))
(bignum-sign-set! nx (bignum-sign x))
(let loop3 ((i 1) (c 0))
(if (##fixnum.< i lx)
(let ((w (##fixnum.+ (##fixnum.* (bignum-digit-ref x i) shift) c)))
(bignum-digit-set! nx i (##fixnum.modulo w (radix)))
(loop3 (##fixnum.+ i 1) (##fixnum.quotient w (radix))))
(bignum-digit-set! nx i c)))
(let loop4 ((i 1) (c 0))
(if (##fixnum.< i ly)
(let ((w (##fixnum.+ (##fixnum.* (bignum-digit-ref y i) shift) c)))
(bignum-digit-set! ny i (##fixnum.modulo w (radix)))
(loop4 (##fixnum.+ i 1) (##fixnum.quotient w (radix))))))
(let loop5 ((i lx))
(if (##not (##fixnum.< i ly))
; STEP 2: calculate next digit in quotient
(let ((msd-of-ny
(bignum-digit-ref ny (##fixnum.- ly 1)))
(next-msd-of-ny
(bignum-digit-ref ny (##fixnum.- ly 2)))
(msd-of-nx
(bignum-digit-ref nx i))
(next-msd-of-nx
(bignum-digit-ref nx (##fixnum.- i 1)))
(next-next-msd-of-nx
(bignum-digit-ref nx (##fixnum.- i 2))))
(define (next-digit q u)
(if (##fixnum.< u (radix))
(let* ((temp1 (##fixnum.* q next-msd-of-ny))
(temp2 (##fixnum.quotient temp1 (radix))))
(if (or (##fixnum.< u temp2)
(and (##eq? temp2 u)
(##fixnum.<
next-next-msd-of-nx
(##fixnum.remainder temp1 (radix)))))
(next-digit (##fixnum.- q 1) (##fixnum.+ u msd-of-ny))
q))
q))
(let ((q (if (##eq? msd-of-nx msd-of-ny)
(next-digit
(radix-minus-1)
(##fixnum.+ msd-of-ny next-msd-of-nx))
(let ((temp (##fixnum.+
(##fixnum.* msd-of-nx (radix))
next-msd-of-nx)))
(next-digit
(##fixnum.quotient temp msd-of-ny)
(##fixnum.modulo temp msd-of-ny))))))
; STEP 3: multiply and substract
(let loop7 ((j 1)
(k (##fixnum.- i (##fixnum.- ly 1)))
(b 0))
(if (##fixnum.< j ly)
(let ((w (##fixnum.-
(##fixnum.+ (bignum-digit-ref nx k) b)
(##fixnum.* (bignum-digit-ref ny j) q))))
(bignum-digit-set! nx k (##fixnum.modulo w (radix)))
(loop7 (##fixnum.+ j 1)
(##fixnum.+ k 1)
(##fixnum.quotient (##fixnum.- w (radix-minus-1))
(radix))))
(let ((w (##fixnum.+ (bignum-digit-ref nx k) b)))
(bignum-digit-set! nx k (##fixnum.modulo w (radix)))
(if (##fixnum.< w 0)
(begin
(bignum-digit-set!
r
(##fixnum.- i (##fixnum.- ly 1))
(##fixnum.- q 1))
(let loop8 ((j 1)
(k (##fixnum.- i (##fixnum.- ly 1)))
(c 0))
(if (##fixnum.< j ly)
(let ((w (##fixnum.+
(##fixnum.+
(bignum-digit-ref nx k)
(bignum-digit-ref ny j))
c)))
(bignum-digit-set!
nx
k
(##fixnum.modulo w (radix)))
(loop8 (##fixnum.+ j 1)
(##fixnum.+ k 1)
(##fixnum.quotient w (radix))))
(bignum-digit-set!
nx
k
(##fixnum.modulo
(##fixnum.+ (bignum-digit-ref nx k) c)
(radix))))))
(bignum-digit-set!
r
(##fixnum.- i (##fixnum.- ly 1))
q))
(loop5 (##fixnum.- i 1)))))))))
(let loop9 ((i (##fixnum.- ly 1)) (k 0))
(if (##fixnum.< 0 i)
(let ((w (##fixnum.+ (##fixnum.* k (radix))
(bignum-digit-ref nx i))))
(bignum-digit-set! nx i (##fixnum.quotient w shift))
(loop9 (##fixnum.- i 1)
(##fixnum.remainder w shift)))))
(##bignum.remove-leading-0s! nx)
(##bignum.remove-leading-0s! r)
(##cons r nx)))))
(define (div x y lx ly)
(if (##fixnum.< lx ly)
(##cons ##bignum.0 x)
(let ((r (bignum-make (##fixnum.+ (##fixnum.- lx ly) 2))))
(if (##eq? (bignum-sign x) (bignum-sign y))
(bignum-set-positive! r)
(bignum-set-negative! r))
(if (##eq? ly 2)
(single-digit-divisor-div x y lx ly r)
(multi-digit-divisor-div x y lx ly r)))))
(div x y (bignum-length x) (bignum-length y)))
; Conversion to string
(define (##bignum.number->string n rad)
(define (bignum->string n rad r r-log-rad radix-log-r-num)
(let ((len (##fixnum.* (##fixnum.quotient
(##fixnum.+
(##fixnum.* (##fixnum.- (bignum-length n) 1)
radix-log-r-num)
(##fixnum.- (radix-log-den) 1))
(radix-log-den))
r-log-rad)))
(let ((n (##bignum.copy n))
(s (##make-string (##fixnum.+ len 1) #\space)))
(define (put-digits k i)
(let loop1 ((k k) (i i) (j r-log-rad) (last-non-zero i))
(if (##fixnum.< 0 j)
(let ((d (##fixnum.remainder k rad)))
(##string-set! s i
(##string-ref "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" d))
(loop1 (##fixnum.quotient k rad)
(##fixnum.- i 1)
(##fixnum.- j 1)
(if (##eq? d 0) last-non-zero i)))
last-non-zero)))
(define (move-digits i j)
(let loop2 ((i i) (j j))
(if (##fixnum.< len i)
(##string-shrink! s j)
(begin
(##string-set! s j (##string-ref s i))
(loop2 (##fixnum.+ i 1) (##fixnum.+ j 1))))))
(let loop3 ((i len))
(let ((k
; k = next digit in base `r'
; use simple algo for dividing in place by `r'
; (which is known to be less than or equal to radix)
(let loop4 ((j (##fixnum.- (bignum-length n) 1)) (k 0))
(if (##fixnum.< 0 j)
(let ((x (##fixnum.+ (##fixnum.* k (radix))
(bignum-digit-ref n j))))
(bignum-digit-set! n j (##fixnum.quotient x r))
(loop4 (##fixnum.- j 1) (##fixnum.remainder x r)))
k))))
(let ((last-non-zero (put-digits k i)))
(##bignum.remove-leading-0s! n)
(if (##not (bignum-zero? n))
(loop3 (##fixnum.- i r-log-rad))
(if (bignum-negative? n)
(begin
(##string-set! s 0 #\-)
(move-digits last-non-zero 1))
(move-digits last-non-zero 0)))))))))
(cond ((##eq? rad 2)
(bignum->string n rad (r.2) (r-log-rad.2) (radix-log-r-num.2)))
((##eq? rad 8)
(bignum->string n rad (r.8) (r-log-rad.8) (radix-log-r-num.8)))
((##eq? rad 10)
(bignum->string n rad (r.10) (r-log-rad.10) (radix-log-r-num.10)))
(else
(bignum->string n rad (r.16) (r-log-rad.16) (radix-log-r-num.16)))))
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Utilities:
(define (##bignum.copy x)
(let ((len (bignum-length x)))
(let ((y (bignum-make len)))
(let loop ((i (##fixnum.- len 1)))
(if (##fixnum.< i 0)
y
(begin
(bignum-digit-set! y i (bignum-digit-ref x i))
(loop (##fixnum.- i 1))))))))
(define (##bignum.remove-leading-0s! x)
(let ((sign (bignum-sign x)))
(bignum-sign-set! x 1) ; set to something different than 0
(let loop ((i (##fixnum.- (bignum-length x) 1)))
(if (##eq? (bignum-digit-ref x i) 0)
(loop (##fixnum.- i 1))
(bignum-shrink! x (##fixnum.+ i 1))))
(bignum-sign-set! x sign)))
(define (##bignum.normalize x)
(let ((lx-minus-1 (##fixnum.- (bignum-length x) 1)))
(if (##fixnum.< (max-digits-for-fixnum) lx-minus-1)
x
(let loop ((n 0) (i lx-minus-1))
(cond ((##fixnum.< 0 i)
(if (##fixnum.< n (min-fixnum-div-radix))
x
(let ((y (##fixnum.- (##fixnum.* n (radix))
(bignum-digit-ref x i))))
(if (##fixnum.< y 0)
(loop y (##fixnum.- i 1))
x))))
((bignum-negative? x)
n)
(else
(let ((n (##fixnum.- 0 n)))
(if (##fixnum.< n 0) x n))))))))
(define (##bignum.<-fixnum n)
(if (or (##fixnum.< n -16) (##fixnum.< 16 n))
(##bignum.<-fixnum* n)
(##vector-ref ##bignum.constants (##fixnum.+ n 16))))
(define (##bignum.<-fixnum* n)
(let ((neg-n (if (##fixnum.< n 0) n (##fixnum.- 0 n))))
(let loop1 ((nb-digits 0) (x neg-n))
(if (##not (##eq? x 0))
(loop1 (##fixnum.+ nb-digits 1) (##fixnum.quotient x (radix)))
(let ((r (bignum-make (##fixnum.+ nb-digits 1))))
(if (##fixnum.< n 0)
(bignum-set-negative! r)
(bignum-set-positive! r))
(let loop2 ((i 1) (x neg-n))
(if (##not (##eq? x 0))
(begin
(bignum-digit-set!
r
i
(##fixnum.- 0 (##fixnum.remainder x (radix))))
(loop2 (##fixnum.+ i 1) (##fixnum.quotient x (radix))))
r)))))))
(define ##bignum.constants
(let ((v (##make-vector 33 #f)))
(let loop ((i 0) (n -16))
(if (##not (##fixnum.< 16 n))
(begin
(##vector-set! v i (##bignum.<-fixnum* n))
(loop (##fixnum.+ i 1) (##fixnum.+ n 1)))))
v))
(define ##bignum.0
(##bignum.<-fixnum 0))
(define ##bignum.2*min-fixnum
(##bignum.* (##bignum.<-fixnum (min-fixnum)) (##bignum.<-fixnum 2)))
;------------------------------------------------------------------------------
; Ratnum operations
; -----------------
(define (##ratnum.= x y)
(and (##= (ratnum-numerator x) (ratnum-numerator y))
(##= (ratnum-denominator x) (ratnum-denominator y))))
(define (##ratnum.< x y)
(##< (##* (ratnum-numerator x) (ratnum-denominator y))
(##* (ratnum-denominator x) (ratnum-numerator y))))
(define (##ratnum.+ x y)
(##ratnum.normalize
(##+ (##* (ratnum-numerator x) (ratnum-denominator y))
(##* (ratnum-denominator x) (ratnum-numerator y)))
(##* (ratnum-denominator x) (ratnum-denominator y))))
(define (##ratnum.* x y)
(##ratnum.normalize
(##* (ratnum-numerator x) (ratnum-numerator y))
(##* (ratnum-denominator x) (ratnum-denominator y))))
(define (##ratnum.- x y)
(##ratnum.normalize
(##- (##* (ratnum-numerator x) (ratnum-denominator y))
(##* (ratnum-denominator x) (ratnum-numerator y)))
(##* (ratnum-denominator x) (ratnum-denominator y))))
(define (##ratnum./ x y)
(##ratnum.normalize
(##* (ratnum-numerator x) (ratnum-denominator y))
(##* (ratnum-denominator x) (ratnum-numerator y))))
(define (##ratnum.floor x)
(let ((num (ratnum-numerator x))
(den (ratnum-denominator x)))
(if (##negative? num)
(##quotient (##- num (##- den 1)) den)
(##quotient num den))))
(define (##ratnum.ceiling x)
(let ((num (ratnum-numerator x))
(den (ratnum-denominator x)))
(if (##negative? num)
(##quotient num den)
(##quotient (##+ num (##- den 1)) den))))
(define (##ratnum.truncate x)
(##quotient (ratnum-numerator x) (ratnum-denominator x)))
(define (##ratnum.round x)
(let ((num (ratnum-numerator x))
(den (ratnum-denominator x)))
(if (##eq? den 2)
(if (##negative? num)
(##* (##quotient (##- num 1) 4) 2)
(##* (##quotient (##+ num 1) 4) 2))
(##floor (##ratnum.normalize (##+ (##* num 2) den) (##* den 2))))))
(define (##ratnum.normalize num den)
(let ((x (##gcd num den)))
(let ((y (if (##negative? den) (##- 0 x) x)))
(let ((num (##quotient num y))
(den (##quotient den y)))
(if (##eq? den 1)
num
(ratnum-make num den))))))
(define (##ratnum.<-exact-int x)
(ratnum-make x 1))
;------------------------------------------------------------------------------
; Flonum operations
; -----------------
(define-system (##flonum.->fixnum x))
(define-system (##flonum.<-fixnum x))
(define-nary0 (##flonum.+ x y) (inexact-0) x (##flonum.+ x y) no-touch)
(define-nary0 (##flonum.* x y) (inexact-+1) x (##flonum.* x y) no-touch)
(define-nary1 (##flonum.- x y) (##flonum.- (inexact-0) x) (##flonum.- x y) no-touch)
(define-nary1 (##flonum./ x y) (##flonum./ (inexact-+1) x) (##flonum./ x y) no-touch)
(define-system (##flonum.abs x))
(define-system (##flonum.floor x)
(let ((y (##flonum.truncate x)))
(if (or (##flonum.= x y) (##flonum.positive? x))
y
(##flonum.- y (inexact-+1)))))
(define-system (##flonum.ceiling x)
(let ((y (##flonum.truncate x)))
(if (or (##flonum.= x y) (##flonum.negative? x))
y
(##flonum.+ y (inexact-+1)))))
(define-system (##flonum.truncate x))
(define-system (##flonum.round x))
(define-system (##flonum.exp x))
(define-system (##flonum.log x))
(define-system (##flonum.sin x))
(define-system (##flonum.cos x))
(define-system (##flonum.tan x))
(define-system (##flonum.asin x))
(define-system (##flonum.acos x))
(define-system (##flonum.atan x))
(define-system (##flonum.sqrt x))
(define-system (##flonum.zero? x)
(##flonum.= x (inexact-0)))
(define-system (##flonum.positive? x)
(##flonum.< (inexact-0) x))
(define-system (##flonum.negative? x)
(##flonum.< x (inexact-0)))
(define-nary0-boolean (##flonum.= x y)
(##flonum.= x y) no-check no-touch)
(define-nary0-boolean (##flonum.< x y)
(##flonum.< x y) no-check no-touch)
(define-nary0-boolean (##flonum.> x y)
(##flonum.< y x) no-check no-touch)
(define-nary0-boolean (##flonum.<= x y)
(##not (##flonum.< y x)) no-check no-touch)
(define-nary0-boolean (##flonum.>= x y)
(##not (##flonum.< x y)) no-check no-touch)
(define (##flonum.<-ratnum x)
(##flonum./ (##exact->inexact (ratnum-numerator x))
(##exact->inexact (ratnum-denominator x))))
(define (##flonum.<-bignum x)
(let ((lx (bignum-length x)))
(let loop ((i (##fixnum.- lx 1)) (res (inexact-0)))
(if (##fixnum.< 0 i)
(loop (##fixnum.- i 1)
(##flonum.+ (##flonum.* res (inexact-radix))
(##flonum.<-fixnum (bignum-digit-ref x i))))
(if (bignum-negative? x)
(##flonum.- (inexact-0) res)
res)))))
(define (##flonum.->exact-int x)
(let loop1 ((z (##flonum.abs x)) (n 1))
(if (##flonum.< (inexact-radix) z)
(loop1 (##flonum./ z (inexact-radix)) (##fixnum.+ n 1))
(let loop2 ((res 0) (z z) (n n))
(if (##fixnum.< 0 n)
(let ((truncated-z (##flonum.truncate z)))
(loop2 (##+ (##flonum.->fixnum truncated-z) (##* res (radix)))
(##flonum.* (##flonum.- z truncated-z) (inexact-radix))
(##fixnum.- n 1)))
(if (##flonum.negative? x)
(##- 0 res)
res))))))
(define (##flonum.->inexact-exponential-format x)
(define (exp-form-pos x y i)
(let ((i*2 (##fixnum.+ i i)))
(let ((z (if (and (##not (##fixnum.< (flonum-e-bias) i*2))
(##not (##flonum.< x y)))
(exp-form-pos x (##flonum.* y y) i*2)
(##cons x 0))))
(let ((a (##car z)) (b (##cdr z)))
(let ((i+b (##fixnum.+ i b)))
(if (and (##not (##fixnum.< (flonum-e-bias) i+b))
(##not (##flonum.< a y)))
(begin
(##set-car! z (##flonum./ a y))
(##set-cdr! z i+b)))
z)))))
(define (exp-form-neg x y i)
(let ((i*2 (##fixnum.+ i i)))
(let ((z (if (and (##fixnum.< i*2 (flonum-e-bias-minus-1))
(##flonum.< x y))
(exp-form-neg x (##flonum.* y y) i*2)
(##cons x 0))))
(let ((a (##car z)) (b (##cdr z)))
(let ((i+b (##fixnum.+ i b)))
(if (and (##fixnum.< i+b (flonum-e-bias-minus-1))
(##flonum.< a y))
(begin
(##set-car! z (##flonum./ a y))
(##set-cdr! z i+b)))
z)))))
(define (exp-form x)
(if (##flonum.< x (inexact-+1))
(let ((z (exp-form-neg x (inexact-+1/2) 1)))
(##set-car! z (##flonum.* (inexact-+2) (##car z)))
(##set-cdr! z (##fixnum.- -1 (##cdr z)))
z)
(exp-form-pos x (inexact-+2) 1)))
(if (##flonum.negative? x)
(let ((z (exp-form (##flonum.abs x))))
(##set-car! z (##flonum.- (inexact-0) (##car z)))
z)
(exp-form x)))
(define (##flonum.->exact-exponential-format x)
(let ((z (##flonum.->inexact-exponential-format x)))
(let ((y (##car z)))
(cond ((##not (##flonum.< y (inexact-+2)))
(##set-car! z (flonum-+m-min))
(##set-cdr! z (flonum-e-bias-plus-1)))
((##not (##flonum.< (inexact--2) y))
(##set-car! z (flonum--m-min))
(##set-cdr! z (flonum-e-bias-plus-1)))
(else
(##set-car! z (##flonum.->exact-int (##flonum.* (##car z) (flonum-m-min))))))
(##set-cdr! z (##fixnum.- (##cdr z) (flonum-m-bits)))
z)))
(define (##flonum.inexact->exact x)
(let ((z (##flonum.->exact-exponential-format x)))
(##* (##car z) (##expt 2 (##cdr z)))))
(define (##flonum.->bits x)
(define (bits a b)
(if (##< a (flonum-+m-min))
a
(##+ (##- a (flonum-+m-min))
(##* (##fixnum.+ (##fixnum.+ b (flonum-m-bits)) (flonum-e-bias))
(flonum-+m-min)))))
(let ((z (##flonum.->exact-exponential-format x)))
(let ((a (##car z)) (b (##cdr z)))
(if (##negative? a)
(##+ (flonum-sign-bit) (bits (##- 0 a) b))
(bits a b)))))
(define (##flonum.->ratnum x)
(let ((y (##flonum.inexact->exact x)))
(if (exact-int? y)
(##ratnum.<-exact-int y)
y)))
;------------------------------------------------------------------------------
; Cpxnum operations
; -----------------
(define (##cpxnum.= x y)
(and (##= (cpxnum-real x) (cpxnum-real y))
(##= (cpxnum-imag x) (cpxnum-imag y))))
(define (##cpxnum.+ x y)
(let ((a (cpxnum-real x)) (b (cpxnum-imag x))
(c (cpxnum-real y)) (d (cpxnum-imag y)))
(##make-rectangular (##+ a c) (##+ b d))))
(define (##cpxnum.* x y)
(let ((a (cpxnum-real x)) (b (cpxnum-imag x))
(c (cpxnum-real y)) (d (cpxnum-imag y)))
(##make-rectangular (##- (##* a c) (##* b d)) (##+ (##* a d) (##* b c)))))
(define (##cpxnum.- x y)
(let ((a (cpxnum-real x)) (b (cpxnum-imag x))
(c (cpxnum-real y)) (d (cpxnum-imag y)))
(##make-rectangular (##- a c) (##- b d))))
(define (##cpxnum./ x y)
(let ((a (cpxnum-real x)) (b (cpxnum-imag x))
(c (cpxnum-real y)) (d (cpxnum-imag y)))
(let ((q (##+ (##* c c) (##* d d))))
(##make-rectangular (##/ (##+ (##* a c) (##* b d)) q)
(##/ (##- (##* b c) (##* a d)) q)))))
(define (##cpxnum.<-non-cpxnum x)
(cpxnum-make x 0))
;------------------------------------------------------------------------------